﻿using System;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.IdentityFramework;
using Abp.Runtime.Session;
using SingleUserMall.Authorization.Users;
using SingleUserMall.MultiTenancy;
using SingleUserMall.Users;
using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security.OAuth;
using Abp.Configuration;
using Abp.Authorization;
using Microsoft.Owin.Security;
using Microsoft.Extensions.Internal;
using SingleUserMall.Authorization;
using SingleUserMall.Orders;
using Abp.Domain.Repositories;
using Abp.UI;
using System.Web;
using System.IO;
using SingleUserMall.Items;

namespace SingleUserMall
{
    /// <summary>
    /// Derive your application services from this class.
    /// </summary>
    public abstract class SingleUserMallAppServiceBase : ApplicationService
    {
        public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
        public TenantManager TenantManager { get; set; }
        public SettingManager SettingManager { get; set; }
        public UserManager UserManager { get; set; }
        public Authorization.Roles.RoleManager RoleManager { get; set; }
        public LogInManager LogInManager { get; set; }
        public OrderManager OrderManager { get; set; }
        public ItemManager ItemManager { get; set; }
        static SingleUserMallAppServiceBase()
        {
            OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        }

        protected SingleUserMallAppServiceBase()
        {
            LocalizationSourceName = SingleUserMallConsts.LocalizationSourceName;
        }

        protected virtual Task<User> GetCurrentUserAsync()
        {
            var user = UserManager.FindByIdAsync(AbpSession.GetUserId());
            if (user == null)
            {
                throw new ApplicationException("There is no current user!");
            }

            return user;
        }

        protected virtual Task<Tenant> GetCurrentTenantAsync()
        {
            return TenantManager.GetByIdAsync(AbpSession.GetTenantId());
        }

        protected virtual void CheckErrors(IdentityResult identityResult)
        {
            identityResult.CheckErrors(LocalizationManager);
        }

        protected Exception CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress)
        {
            switch (result)
            {
                case AbpLoginResultType.Success:
                    return new ApplicationException("Don't call this method with a success result!");
                case AbpLoginResultType.InvalidUserNameOrEmailAddress:
                case AbpLoginResultType.InvalidPassword:
                    return new UserFriendlyException(L("InvalidUserNameOrPassword"));
                case AbpLoginResultType.UserIsNotActive:
                    return new UserFriendlyException(L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));
                case AbpLoginResultType.UserEmailIsNotConfirmed:
                    return new UserFriendlyException(L("LoginFailed")); //TODO: localize message
                case AbpLoginResultType.LockedOut:
                    return new UserFriendlyException(L("LockedOut"));
                default: //Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
                    Logger.Warn("Unhandled login fail reason: " + result);
                    return new UserFriendlyException(L("LoginFailed"));
            }
        }

        protected async Task<string> CreateTokenAsync(User user)
        {
            var loginIdentity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ExternalBearer);
            var ticket = new AuthenticationTicket(loginIdentity, new AuthenticationProperties());
            var currentUtc = new SystemClock().UtcNow;
            ticket.Properties.IssuedUtc = currentUtc;
            ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromDays(90));
            var token = OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
            return token;
        }

        /// <summary>
        /// 上传文件获取url,path,size,key
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        protected (string, string, int, string) Upload(HttpPostedFile file)
        {
            var mapPath = string.Format("/Uploads/Files/{0}/", AbpSession.UserId?.ToString() ?? "0");
            if (file != null)
            {
                var size = (int)(file.ContentLength / 1024);
                var id = Guid.NewGuid().ToString("N");
                string fileName = file.FileName;
                string fileType = fileName.Substring(fileName.LastIndexOf(".") + 1);
                string folder = HttpContext.Current.Request.MapPath("~" + mapPath);
                //自动创建文件夹
                if (!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }
                var newFileName = id + "." + fileType;
                var path = Path.Combine(folder, newFileName);
                file.SaveAs(path);
                var fileUrl = mapPath + newFileName;
                return (fileUrl, path, size, newFileName);
            }
            throw new UserFriendlyException("文件不存在");
        }
    }
}